#include "audio.h"

#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>

#include <al.h>
#include <alc.h>
#include <alut.h>

Audio* Audio::_instance = 0;

Audio* Audio::Instance(){

	if (_instance == 0){
	
		_instance = new Audio;
	}
	return _instance;
}

// Constructor ***************************************************************************************************
Audio::Audio()
{
	alDevice	= NULL;
	alContext	= NULL;
}


// Destructor ****************************************************************************************************
Audio::~Audio()
{
}

// Init ***************************************************************************************************
bool Audio::Init()
{	
	alDevice = alcOpenDevice(NULL);
	if (alDevice == NULL)
	{
		MessageBox (NULL,"Error: Failed to Open Device", NULL, MB_OK);
		return (false);
	}

	alContext = alcCreateContext(alDevice, NULL);
	if (alContext == NULL)
	{
		MessageBox (NULL, "Error: Failed to initialize OpenAL", NULL, MB_OK);
		return (false);
	}

	alcMakeContextCurrent(alContext);
	if (alcGetError(alDevice) != ALC_NO_ERROR)
	{
		MessageBox (NULL, "Error: Failed to Make Context Current", NULL, MB_OK);
		return (false);
	}

	return true;
}

// Release *******************************************************************************************************
void Audio::Release()
{
	if (alDevice == NULL || alContext == NULL) return;

	alcDestroyContext(alContext);
	alcCloseDevice(alDevice);

	alContext	= NULL;
	alDevice	= NULL;
}

// SetListener ************************************************************************************************************
void Audio::SetListener(float x, float y, float z, float player_angle)
{
	ALfloat rad				= (3.141592654f / 180.0f) * player_angle;
	ALfloat position[]		= {x, y, z};
	ALfloat orientation[]	= {(float)sin(rad), 0, (float)-cos(rad), 0,0,0};

	alGetError();
	alcGetError(alDevice);

	alListenerfv(AL_POSITION, position);
	if (alGetError() != AL_NO_ERROR)
	{
		MessageBox (NULL, "Failed to Set the Listener Position", NULL, MB_OK);
		return;
	}

	alListenerfv(AL_ORIENTATION, orientation);
	if (alGetError() != AL_NO_ERROR)
	{
		MessageBox (NULL, "Failed to Set the Listener Orientation", NULL, MB_OK);
		return;
	}
}

bool Audio::deleteBuffer(unsigned int* id){

	if(!alDevice)
		return false;

	alDeleteBuffers(1, id);
	if (alcGetError(alDevice) != ALC_NO_ERROR)
	{
		MessageBox (NULL, "Error: Failed to delete buffer", NULL, MB_OK);
		return (false);
	}
	
	return true;
}

bool Audio::setSource(unsigned int id, long buffer, float x, float y, float z, float gain, bool loop)
{
	if(!alDevice)
		return false;

	ALint value;
	alGetSourcei(id, AL_SOURCE_STATE, &value);
	if(value==AL_PLAYING)
		return false;

	ALfloat position[] = {x, y, z};

	alSourcei(id, AL_BUFFER, buffer);
	alSourcef(id, AL_PITCH, 1);
	alSourcef(id, AL_GAIN, gain);
	alSourcefv(id, AL_POSITION, position);		
	alSourcei(id, AL_LOOPING, loop);

	return true;
}

bool Audio::isPlaying(unsigned int id){

	ALint value;

	alGetSourcei(id, AL_SOURCE_STATE, &value);
	if(value==AL_PLAYING)
		return true;

	return false;
}

void Audio::playSource(unsigned int id)
{
	if(!alDevice)
		return;

	ALint value;
	alGetSourcei(id, AL_SOURCE_STATE, &value);
	if(value==AL_PLAYING)
		return;

	alSourcePlay(id);	
	if (alGetError() != AL_NO_ERROR)
	{
		char errmsg[50];
		sprintf (errmsg, "Error: Failed to Play Source %i", id);
		MessageBox (NULL, errmsg, NULL, MB_OK);
	} 	
}

void Audio::stopSource(long id)
{	
	if(!alDevice)
		return;

	alSourceStop(id);
	if (alGetError() != AL_NO_ERROR)
	{
		char errmsg[50];
		sprintf (errmsg, "Error: Failed to Stop Source %i", id);
		MessageBox (NULL, errmsg, NULL, MB_OK);
	}
}

void Audio::deleteSource(unsigned int* id)
{
	if(!alDevice)
		return;

	alDeleteSources(1, id);
	if (alcGetError(alDevice) != ALC_NO_ERROR)
	{
		MessageBox (NULL, "Error: Failed to delete source", NULL, MB_OK);
//		return (false);
	}
}

void Audio::genSource(unsigned int* id)
{
	if(!alDevice)
		return;

	alGenSources(1, id);
	if (alcGetError(alDevice) != ALC_NO_ERROR)
	{
		MessageBox (NULL, "Error: Failed to create source", NULL, MB_OK);
//		return (false);
	}
}

bool Audio::loadWave(char* buffer, unsigned int* bfr){
	if(!alDevice)
		return false;

	char		errmsg[500];
	ALsizei		size;
	ALsizei		freq;
	ALenum		format;
	ALvoid		*data;
	ALboolean	loop;

	alutLoadWAVFile(buffer, &format, &data, &size, &freq, &loop);
	if (alGetError() != AL_NO_ERROR)
	{
		sprintf (errmsg, "Error: Failed to Load WAV (%s)", bfr);
		MessageBox (NULL, errmsg, NULL, MB_OK);				

		return false;
	}

	alGenBuffers(1, bfr);
	if (alGetError() != AL_NO_ERROR)
	{
		MessageBox (NULL, "Error: Failed to Generate Buffers", NULL, MB_OK);
		return false;
	}

	alBufferData(*bfr, format, data, size, freq);
	if (alGetError() != AL_NO_ERROR)
	{		
		sprintf (errmsg, "Error: Failed to Copy Buffer Data %i (%s)", buffer, bfr);
		MessageBox (NULL, errmsg, NULL, MB_OK);		

		return false;
	}

	alutUnloadWAV(format, data, size, freq);
	if (alGetError() != AL_NO_ERROR)
	{		
		sprintf (errmsg, "Error: Failed to Unload WAV Data (%s)", bfr);
		MessageBox (NULL, errmsg, NULL, MB_OK);	

		return false;
	}

	return true;
}

void Audio::moveTo(unsigned int id, float x, float y, float z){

	alSource3f(id, AL_POSITION, x, y, z);
	if (alcGetError(alDevice) != ALC_NO_ERROR)
	{
		MessageBox (NULL, "Error: Failed to move source", NULL, MB_OK);
//		return (false);
	}
}
